package yicr.untils.gis.mif;



import lombok.extern.slf4j.Slf4j;
import yicr.untils.NslUtilCollection;
import yicr.untils.NslUtilCsv;
import yicr.untils.NslUtilFile;
import yicr.untils.NslUtilString;
import yicr.untils.datetime.NslUtilDateTime;
import yicr.untils.gis.Polygon.NslPolygon;
import yicr.untils.gis.domain.NslGpsPoint;
import yicr.untils.gis.mif.domain.MifFileObject;
import yicr.untils.gis.mif.domain.MifRegion;


import java.awt.geom.Point2D;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;


/**
 * <h3>Title:</h3>
 * <p>
 *
 * <h3>Description</h3>
 * <p>
 *
 * <h3>Author</h3>
 * <p>
 * Lin Shao
 * <h3>Update Time</h3>
 * <p>2021-05-21 16:06
 *
 * @author Lin Shao
 * @version 1.0
 */
@Slf4j
public class UtilMapInfoMif {

    /**
     * convert polygonList to Mif and Mid  files.
     * The mid file only have one column named Id which is defined as Char(40)
     * @param polygonListFilePath the file is csv format Which has only two columns.One is used as Id information. Another is polygon points which are clockwise as the mapinfo required.
     *  The polygon points format are like this "113.658340;34.757690_113.660080;34.758030_113.661170;34.758200".
     *
     */
    static public void parseIdPolygonList2MifAndMid(String polygonListFilePath,String outputMifPath) throws Exception {
        if(polygonListFilePath.toLowerCase().endsWith(".mif")){
            outputMifPath=outputMifPath.toLowerCase().replaceAll(".mif","");

        }
        String mifFileAbsPath=outputMifPath+".MIF";
        String midFileAbsPath=outputMifPath+".MID";


        MifFileObject mifFileObject=new MifFileObject();

        String fileTitle= "Version   300\n" +
                "Charset \"WindowsSimpChinese\"\n" +
                "Delimiter \",\"\n" +
                "CoordSys Earth Projection 1, 104\n" +
                "Columns 1\n" +
                "  ID Char(40)\n" +
                "Data\n";

        mifFileObject.setTitle(fileTitle);

        
        List<String> lineList=NslUtilCsv.readCsvFile(new File(polygonListFilePath));
        List<String> idList=new ArrayList<>();

        for (int i = 1; i < lineList.size(); i++) {
            //line = "idstring,113.658340;34.757690_113.660080;34.758030_113.661170;34.758200"
            String line=lineList.get(i);
            String[] columns=line.split(",");
            idList.add(columns[0]);
        }

        List<MifRegion> mifRegionList= lineStringList2MifRegionList(lineList,true);

        mifFileObject.getMifRegionList().addAll(mifRegionList);

        createMifFile(mifFileAbsPath,mifFileObject,false);
        NslUtilCsv.writeCsvFile(new File(midFileAbsPath),idList);
    }

    /**
     * 根据 polygonList 生成 mif和mid文件
     * @param polygonList
     * @param outputFilePath
     */
    static public void buildMifAndMidFilesByPolygonList(List<NslPolygon> polygonList, String outputFilePath ) throws Exception {
        List<String> lineRecordList=convertPolygonList2LineRecordList(polygonList);
        lineStringListOfPolygon2MifAndMid(lineRecordList,outputFilePath,false);
    }

    /**
     * 讲 polyList中个每个元素，转换成 字符串List
     * 每个字符串形式如下： "idString,113.658340;34.757690_113.660080;34.758030_113.661170;34.758200"
     * @param polygonList
     * @return
     */
    private static List<String> convertPolygonList2LineRecordList(List<NslPolygon> polygonList) {
        if(NslUtilCollection.isNullOrEmpty(polygonList)){
            throw new RuntimeException("出入的 polygonList 为空");
        }

        List<String> recordLineList=new ArrayList<>();
        for (NslPolygon nslPolygon : polygonList) {
            StringBuffer gpsInfo=new StringBuffer();
            for (Point2D.Double point : nslPolygon.getPointList()) {
                gpsInfo.append(point.getX()).append(";").append(point.getY()).append("_");
            }
            String gpsString=gpsInfo.toString();
            gpsString= NslUtilString.deleteTail(gpsString,1);
            String lineRecord=nslPolygon.getId()+","+gpsString;
            recordLineList.add(lineRecord);
//            log.info("recordLineList = {} ",recordLineList);
        }
        return recordLineList;
    }

    /**
     * 根据csv 文件生成 mif和mid 文件
     * 其中csv文件，要求表头包含  id,region字段
     * 其中region字段格式如：113.658340;34.757690_113.660080;34.758030_113.661170;34.758200
     * @param csvFilePath 文件编码为utf8格式，可以带bom或者不带bom,
     * @param outputFilePath
     */
    public static void buildMifAndMidByCsvFile(String csvFilePath,String outputFilePath) throws Exception {
       List<String> lineList=NslUtilCsv.readCsvFile(new File(csvFilePath));
        System.out.println(NslUtilFile.detectEncoding(new File(csvFilePath)));
        String headLine=lineList.get(0);
        byte[] bytes=headLine.getBytes();
//        String hexString= NslUtilBinaryConversion.bytesToHex(bytes);
//        System.out.println(hexString);

        String[] columnTitleArray=headLine.split(",");
       List<String> stringList=Arrays.asList(columnTitleArray);
//        System.out.println(stringList);
//        System.out.println(stringList.get(0));
//        System.out.println(stringList.get(0).length());
//        System.out.println("id".length());
        int idIndex=stringList.indexOf("id");
        idIndex=stringList.indexOf(stringList.get(0));
        int regionIndex=stringList.indexOf("region");
       if(idIndex==-1 || regionIndex == -1){
           throw new RuntimeException("csv 文件缺少id 或者 region 字段");
       }
       List<String> recordList=new ArrayList<>();
        for (int i = 1; i < lineList.size(); i++) {
            String line=lineList.get(i);
            String[] contents=line.split(",");
            String id=contents[idIndex];
            String region=contents[regionIndex];
            String recordLine=id+","+region;
            recordList.add(recordLine);
        }
        lineStringListOfPolygon2MifAndMid(recordList,outputFilePath,false);

    }


    /**
     *  create Mif And Mid Files by lineList like "idString,113.658340;34.757690_113.660080;34.758030_113.661170;34.758200"
     * mapinfo 读取mid文件时，是以gbk编码读取的，因此需要将mid文件转化成gbk格式
     * @param lineList
     * @param outputMifPath
     */
    static public void lineStringListOfPolygon2MifAndMid(List<String> lineList,String outputMifPath,boolean isHeadLineExist) throws Exception {

        String mifFileAbsPath=outputMifPath+"_"+ NslUtilDateTime.getDateStringAsDd_Hh_Mm_SS() +".MIF";
        String midFileAbsPath=outputMifPath+"_"+NslUtilDateTime.getDateStringAsDd_Hh_Mm_SS() +".MID";
        MifFileObject mifFileObject=new MifFileObject();

        String fileTitle= "Version   300\n" +
                "Charset \"WindowsSimpChinese\"\n" +
                "Delimiter \",\"\n" +
                "CoordSys Earth Projection 1, 104\n" +
                "Columns 1\n" +
                "  ID Char(40)\n" +
                "Data\n";

        mifFileObject.setTitle(fileTitle);
        List<MifRegion> mifRegionList=lineStringList2MifRegionList(lineList,isHeadLineExist);
        mifFileObject.getMifRegionList().addAll(mifRegionList);
        List<String> idList=new ArrayList<>();
        int i=0;

        for (i=isHeadLineExist?1:0; i < lineList.size(); i++) {
            //line = "idstring,113.658340;34.757690_113.660080;34.758030_113.661170;34.758200"
            String line=lineList.get(i);
            String[] columns=line.split(",");
            idList.add(columns[0]);
        }
        createMifFile(mifFileAbsPath,mifFileObject,false);
        NslUtilCsv.writeCsvFile(new File(midFileAbsPath),idList);
    }



    /**
     *
     * @param lineList line like this "idString,113.658340;34.757690_113.660080;34.758030_113.661170;34.758200".
     * @return
     */
    static public  List<MifRegion> lineStringList2MifRegionList(List<String> lineList,boolean isHeadLineExist){
        List<MifRegion> mifRegionList=new ArrayList<>();
        int i=(isHeadLineExist ? 1:0);
//        logger.debug("begin line no. "+i);

        for (; i < lineList.size(); i++) {
            //line = "idstring,113.658340;34.757690_113.660080;34.758030_113.661170;34.758200"
            String line=lineList.get(i);
//            logger.debug("line"+i+" : "+line);
            //System.out.println(line);
            String[] columns=line.split(",");
            //idList.add(columns[0]);
            //String idString=columns[0];
            String pointsString=columns[1];
            String[] pointArray=pointsString.split("_");
            List<NslGpsPoint> pointGisList=new ArrayList<>();
            for (int j = 0; j < pointArray.length; j++) {
                String[] pointString=pointArray[j].split(";");
                NslGpsPoint pointGis=new NslGpsPoint(null,Double.parseDouble(pointString[0]),Double.parseDouble(pointString[1]));
                pointGisList.add(pointGis);
            }
            String[] firstPointString=pointArray[0].split(";");
            NslGpsPoint firstPoint=new NslGpsPoint(null,Double.parseDouble(firstPointString[0]),Double.parseDouble(firstPointString[1]));
            pointGisList.add(firstPoint);

           /* for (String s : pointArray) {
                String[] pointString=s.split(";");
                NslGpsPoint pointGis=new NslGpsPoint(null,Double.parseDouble(pointString[0]),Double.parseDouble(pointString[1]));
                pointGisList.add(pointGis);

            }*/

            List<NslGpsPoint>[] pointListArray=new List[1];
            pointListArray[0]=pointGisList;
            MifRegion mifRegion=new MifRegion(pointListArray);
            mifRegionList.add(mifRegion);
        }

        return mifRegionList;
    }

    //根据指定mif文件转换成MifFileObject对象
    static public  MifFileObject parseMifFile(String fileAbsString){
        MifFileObject mifFileObject=new MifFileObject(fileAbsString);
        File file=new File(fileAbsString);
        StringBuffer result =new StringBuffer() ;
        try{
            BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file),"GBK"));//构造一个BufferedReader类来读取文件
            String s = null;

            boolean isTitleOk=false;
            boolean isRegionBlockOk=false;

            StringBuffer titleStringBuffer=new StringBuffer();
            StringBuffer regionStringBuffer=new StringBuffer();

            int lineNumber=0;

            while((s = br.readLine())!=null){//使用readLine方法，一次读一行
                //System.out.println(lineNumber++);
                if(!isTitleOk){
                    if(s.length()>0) {
                        titleStringBuffer.append(s).append("\n");
                        continue;
                    }

                    //titleStringBuffer.append("\n");
                    mifFileObject.setTitle(titleStringBuffer.toString());

                    //System.out.println(mifFileObject.getTitle());

                    isTitleOk=true;
                    continue;
                }

                //System.out.println(s);
                isRegionBlockOk=s.contains("Center");

                if(!isRegionBlockOk){
                    regionStringBuffer.append(s).append("\n");
                    continue;
                }

                String regionString=regionStringBuffer.append(s).toString();
                //System.out.println(regionString);

                regionStringBuffer=new StringBuffer();

                MifRegion mifRegion=parseString2MifRegion(regionString);

                mifFileObject.getMifRegionList().add(mifRegion);
                //isRegionBlockOk=false;

                //break;

                //System.out.println(lineNumber++);
            }
            br.close();
        }catch(Exception e){
            e.printStackTrace();
        }


        return  mifFileObject;
    }

    static public MifRegion parseString2MifRegion(String regionString){

        MifRegion mifRegion=null;

        List<String> list= Arrays.asList(regionString.split("\n"));
        int listSize=list.size();

        if(list.size()==0){
            return mifRegion;
        }

        String reginLineString=list.get(0);
        //System.out.println("reginLineString="+reginLineString);
        //System.out.println(reginLineString.split("\\s+").length);

        String[] debugArray=reginLineString.split("\\s+");

        for (String s : debugArray) {
            System.out.println(s);
        }

        int regionCount=Integer.parseInt(reginLineString.split("\\s+")[1]);

        mifRegion=new MifRegion(regionCount);

        //mifRegion.setRegionLine(list.get(0));
        mifRegion.setPenString(list.get(listSize-3));
        mifRegion.setBrushString(list.get(listSize-2));
        mifRegion.setCenterString(list.get(listSize-1));



        int index=0;
        List<NslGpsPoint> pointGisList=mifRegion.getPolygonListArray()[index];


        for (int i = 2; i <listSize-3; i++) {
            String lineString=list.get(i);
            String[] lineArray=list.get(i).split("\\s+");
           /* System.out.println(list.get(i));
            System.out.println(lineArray.length);
            for (int i1 = 0; i1 < lineArray.length; i1++) {
                System.out.println(lineArray[i1]);
            }*/
            if(lineString.startsWith(" ")){
                index++;
                pointGisList=mifRegion.getPolygonListArray()[index];
                continue;
            }

            double longitude=Double.parseDouble(lineArray[0]);
            double latitude=Double.parseDouble(lineArray[1]);

            NslGpsPoint pointGis=new NslGpsPoint(null,longitude,latitude);
            pointGisList.add(pointGis);

        }



        //MifRegion mifRegion=new MifRegion(2);


        return mifRegion;
    }

    /*
       mif file format:
       "
       title

       Region  $region.count
         array[0]pointList.size()
       longitude latitude
       longitude latitude
       .....
         array[1]pointList.size()
       longitude latitude
       longitude latitude
       .....
       penString
       brushString
       centerString
     */
    static public File createMifFile4Mapinfo(String outputFileAbsPath,MifFileObject mifFileObject) throws Exception {
        boolean spssFlag=false;
        return createMifFile(outputFileAbsPath,mifFileObject,spssFlag);
    }

    //spssFlag为true时，对于大圆套小圆这种，不取小圆
    static public File createMifFile4Spss(String outputFileAbsPath,MifFileObject mifFileObject) throws Exception {
        boolean spssFlag=true;
        return createMifFile(outputFileAbsPath,mifFileObject,spssFlag);
    }


    //spssFlag为true时，对于大圆套小圆这种，不取小圆
    static private File createMifFile(String outputFileAbsPath,MifFileObject mifFileObject,boolean spssFlag)throws  Exception{
        StringBuffer stringBuffer=new StringBuffer();

        if(mifFileObject==null){
            throw new Exception("MifFileObject is null");
        }

        stringBuffer.append(mifFileObject.getTitle()).append("\n");

        List<MifRegion> mifRegionList=mifFileObject.getMifRegionList();

        for (MifRegion mifRegion : mifRegionList) {
            if(spssFlag){
                stringBuffer.append("Region 1").append("\n");
            }else {
                stringBuffer.append("Region ").append(mifRegion.getRegionCount()).append("\n");
            }

            for (List<NslGpsPoint> pointGisList : mifRegion.getPolygonListArray()) {
                //"  2"   point size
                stringBuffer.append("  ").append(pointGisList.size()).append("\n");
                for (NslGpsPoint pointGis : pointGisList) {
                    stringBuffer.append(pointGis.getLongitude()).append(" ").append(pointGis.getLatitude()).append("\n");
                }
                if(spssFlag){
                    break;
                }
            }

            stringBuffer.append(mifRegion.getPenString()).append("\n");
            stringBuffer.append(mifRegion.getBrushString()).append("\n");
            stringBuffer.append(mifRegion.getCenterString()).append("\n");
        }

        String fileString=stringBuffer.toString();
        //System.out.println(fileString);
        File file=new File(outputFileAbsPath);
        NslUtilFile.string2File(fileString,file,"GBK");

        return file;
    }


    //Map<String,>
}
